/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * VizzyForm.java
 *
 * Created on 23.04.2009, 10:16:16
 */

package vizzy.forms;

import java.awt.Color;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeListener;
import java.net.URI;
import java.util.Date;
import java.util.List;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.text.BadLocationException;
import org.apache.log4j.Logger;
import vizzy.comp.FilterDocument;
import vizzy.comp.JScrollHighlightPanel;
import vizzy.comp.LineHeightTextArea;
import vizzy.comp.NewFeaturesPanel;
import vizzy.controller.VizzyController;
import vizzy.listeners.INewFeaturesListener;
import vizzy.listeners.IVizzyView;
import vizzy.model.Conf;
import vizzy.model.HighlightsColorData;
import vizzy.model.SearchResult;
import vizzy.model.SettingsModel;

/**
 *
 * @author sergeil
 */
public class VizzyForm extends javax.swing.JFrame implements IVizzyView {

    private static final Logger log = Logger.getLogger(VizzyForm.class);

    private NewFeaturesPanel newFeaturesPanel;
    private Border searchComboboxBorder;

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jLineNumbersTextArea = new vizzy.comp.LineHeightTextArea();
        jPanel1 = new javax.swing.JPanel();
        jSearchPanel = new javax.swing.JPanel();
        jSearchComboBox = new javax.swing.JComboBox();
        jButton1 = new javax.swing.JButton();
        jFilterCheckbox = new javax.swing.JCheckBox();
        jRegexpCheckbox = new javax.swing.JCheckBox();
        jPanel2 = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTraceTextArea = new javax.swing.JTextArea();
        jScrollHighlight = new vizzy.comp.JScrollHighlightPanel();
        jPanel3 = new javax.swing.JPanel();
        jClearTraceButton = new javax.swing.JButton();
        logTypeCombo = new javax.swing.JComboBox();
        jOnTopCheckbox = new javax.swing.JCheckBox();
        jAutorefreshCheckBox = new javax.swing.JCheckBox();
        jMenuBar1 = new javax.swing.JMenuBar();
        jMenu1 = new javax.swing.JMenu();
        jMenuItem1 = new javax.swing.JMenuItem();
        jMenu3 = new javax.swing.JMenu();
        jWordWrapCheckBoxMenuItem = new javax.swing.JCheckBoxMenuItem();
        jLineNumbersCheckBoxMenuItem = new javax.swing.JCheckBoxMenuItem();
        jSearchVisibleMenuItem = new javax.swing.JCheckBoxMenuItem();
        jMenu2 = new javax.swing.JMenu();
        jMenuItem3 = new javax.swing.JMenuItem();
        jMenuItemDetectPlayer = new javax.swing.JMenuItem();
        jSeparator1 = new javax.swing.JSeparator();
        jMenuItem2 = new javax.swing.JMenuItem();
        jMenuItem4 = new javax.swing.JMenuItem();

        jLineNumbersTextArea.setBackground(new java.awt.Color(204, 204, 204));
        jLineNumbersTextArea.setFont(new java.awt.Font("Courier New", 0, 12));
        jLineNumbersTextArea.setMinimumSize(new java.awt.Dimension(40, 2147483647));
        jLineNumbersTextArea.setPreferredSize(new java.awt.Dimension(40, 500));

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Vizzy Flash Tracer");
        addWindowFocusListener(new java.awt.event.WindowFocusListener() {
            public void windowGainedFocus(java.awt.event.WindowEvent evt) {
            }
            public void windowLostFocus(java.awt.event.WindowEvent evt) {
                formWindowLostFocus(evt);
            }
        });
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                formWindowClosing(evt);
            }
            public void windowDeactivated(java.awt.event.WindowEvent evt) {
                formWindowDeactivated(evt);
            }
        });

        jPanel1.setLayout(new javax.swing.BoxLayout(jPanel1, javax.swing.BoxLayout.Y_AXIS));

        jSearchPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(3, 3, 3, 3));
        jSearchPanel.setMaximumSize(new java.awt.Dimension(32767, 30));
        jSearchPanel.setPreferredSize(new java.awt.Dimension(0, 30));

        jSearchComboBox.setEditable(true);
        jSearchComboBox.setPreferredSize(new java.awt.Dimension(240, 24));
        jSearchComboBox.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                jSearchComboBoxItemStateChanged(evt);
            }
        });
        jSearchComboBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jSearchComboBoxActionPerformed(evt);
            }
        });

        jButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/img/delete2.png"))); // NOI18N
        jButton1.setPreferredSize(new java.awt.Dimension(80, 26));
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jClearActionPerformed(evt);
            }
        });

        jFilterCheckbox.setText("Filter");
        jFilterCheckbox.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
        jFilterCheckbox.setMargin(new java.awt.Insets(0, 0, 0, 0));
        jFilterCheckbox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jFilterCheckboxChecked(evt);
            }
        });

        jRegexpCheckbox.setText("RegExp");
        jRegexpCheckbox.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
        jRegexpCheckbox.setMargin(new java.awt.Insets(0, 0, 0, 0));
        jRegexpCheckbox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jRegexpCheckboxChecked(evt);
            }
        });

        org.jdesktop.layout.GroupLayout jSearchPanelLayout = new org.jdesktop.layout.GroupLayout(jSearchPanel);
        jSearchPanel.setLayout(jSearchPanelLayout);
        jSearchPanelLayout.setHorizontalGroup(
            jSearchPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jSearchPanelLayout.createSequentialGroup()
                .add(jSearchComboBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 150, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jButton1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 40, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                .add(jFilterCheckbox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 80, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .add(10, 10, 10)
                .add(jRegexpCheckbox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(211, Short.MAX_VALUE))
        );
        jSearchPanelLayout.setVerticalGroup(
            jSearchPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jSearchPanelLayout.createSequentialGroup()
                .add(jSearchPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
                    .add(jSearchPanelLayout.createSequentialGroup()
                        .add(5, 5, 5)
                        .add(jSearchPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                            .add(jRegexpCheckbox)
                            .add(jFilterCheckbox))
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 4, Short.MAX_VALUE))
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, jButton1, 0, 0, Short.MAX_VALUE)
                    .add(jSearchComboBox, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        jPanel1.add(jSearchPanel);

        jPanel2.setPreferredSize(new java.awt.Dimension(0, 0));
        jPanel2.setLayout(new javax.swing.BoxLayout(jPanel2, javax.swing.BoxLayout.LINE_AXIS));

        jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        jScrollPane1.setRowHeaderView(jLineNumbersTextArea);

        jTraceTextArea.setFont(new java.awt.Font("Courier New", 0, 12));
        jTraceTextArea.setLineWrap(true);
        jTraceTextArea.addMouseWheelListener(new java.awt.event.MouseWheelListener() {
            public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) {
                jTraceTextAreaMouseWheelMoved(evt);
            }
        });
        jTraceTextArea.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jTraceTextAreaMouseClicked(evt);
            }
            public void mouseExited(java.awt.event.MouseEvent evt) {
                jTraceTextAreaMouseExited(evt);
            }
            public void mousePressed(java.awt.event.MouseEvent evt) {
                jTraceTextAreaMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                jTraceTextAreaMouseReleased(evt);
            }
        });
        jTraceTextArea.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseMoved(java.awt.event.MouseEvent evt) {
                jTraceTextAreaMouseMoved(evt);
            }
        });
        jTraceTextArea.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                jTraceTextAreaKeyPressed(evt);
            }
        });
        jScrollPane1.setViewportView(jTraceTextArea);

        jPanel2.add(jScrollPane1);

        jScrollHighlight.setMaximumSize(new java.awt.Dimension(8, 32767));
        jScrollHighlight.setMinimumSize(new java.awt.Dimension(8, 0));
        jScrollHighlight.setPreferredSize(new java.awt.Dimension(8, 325));

        org.jdesktop.layout.GroupLayout jScrollHighlightLayout = new org.jdesktop.layout.GroupLayout(jScrollHighlight);
        jScrollHighlight.setLayout(jScrollHighlightLayout);
        jScrollHighlightLayout.setHorizontalGroup(
            jScrollHighlightLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(0, 8, Short.MAX_VALUE)
        );
        jScrollHighlightLayout.setVerticalGroup(
            jScrollHighlightLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(0, 274, Short.MAX_VALUE)
        );

        jPanel2.add(jScrollHighlight);

        jPanel1.add(jPanel2);

        jPanel3.setBorder(javax.swing.BorderFactory.createEmptyBorder(3, 3, 3, 7));
        jPanel3.setMinimumSize(new java.awt.Dimension(0, 29));
        jPanel3.setPreferredSize(new java.awt.Dimension(762, 29));

        jClearTraceButton.setText("Clear Log");
        jClearTraceButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jClearTraceButtondeleteActionPerformed(evt);
            }
        });

        logTypeCombo.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Flash Log", "Policy Log" }));
        logTypeCombo.setMinimumSize(new java.awt.Dimension(67, 23));
        logTypeCombo.setPreferredSize(new java.awt.Dimension(72, 23));
        logTypeCombo.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                logTypeComboActionPerformed(evt);
            }
        });

        jOnTopCheckbox.setText("Always on Top");
        jOnTopCheckbox.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
        jOnTopCheckbox.setMargin(new java.awt.Insets(0, 0, 0, 0));
        jOnTopCheckbox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jOnTopCheckboxChecked(evt);
            }
        });

        jAutorefreshCheckBox.setSelected(true);
        jAutorefreshCheckBox.setText("Auto Refresh");
        jAutorefreshCheckBox.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
        jAutorefreshCheckBox.setMargin(new java.awt.Insets(0, 0, 0, 0));
        jAutorefreshCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jAutorefreshCheckBoxjAutorefreshCheckboxChecked(evt);
            }
        });

        org.jdesktop.layout.GroupLayout jPanel3Layout = new org.jdesktop.layout.GroupLayout(jPanel3);
        jPanel3.setLayout(jPanel3Layout);
        jPanel3Layout.setHorizontalGroup(
            jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, jPanel3Layout.createSequentialGroup()
                .add(jAutorefreshCheckBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 110, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                .add(jOnTopCheckbox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 124, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 159, Short.MAX_VALUE)
                .add(jClearTraceButton)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(logTypeCombo, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 117, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
        );
        jPanel3Layout.setVerticalGroup(
            jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.CENTER)
                .add(jAutorefreshCheckBox)
                .add(logTypeCombo, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .add(jClearTraceButton)
                .add(jOnTopCheckbox))
        );

        jPanel1.add(jPanel3);

        jMenu1.setText("Edit");

        jMenuItem1.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_A, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK));
        jMenuItem1.setText("Copy All to Clipboard");
        jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                menuCopyAllClicked(evt);
            }
        });
        jMenu1.add(jMenuItem1);

        jMenuBar1.add(jMenu1);

        jMenu3.setText("View");

        jWordWrapCheckBoxMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_W, java.awt.event.InputEvent.CTRL_MASK));
        jWordWrapCheckBoxMenuItem.setSelected(true);
        jWordWrapCheckBoxMenuItem.setText("Word Wrap");
        jWordWrapCheckBoxMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jWordWrapCheckBoxMenuItemActionPerformed(evt);
            }
        });
        jMenu3.add(jWordWrapCheckBoxMenuItem);

        jLineNumbersCheckBoxMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_L, java.awt.event.InputEvent.CTRL_MASK));
        jLineNumbersCheckBoxMenuItem.setSelected(true);
        jLineNumbersCheckBoxMenuItem.setText("Line Numbers");
        jLineNumbersCheckBoxMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                menuLineNumbersVisibleClicked(evt);
            }
        });
        jMenu3.add(jLineNumbersCheckBoxMenuItem);

        jSearchVisibleMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F, java.awt.event.InputEvent.CTRL_MASK));
        jSearchVisibleMenuItem.setText("Search Panel ");
        jSearchVisibleMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                menuSearchVisibleClicked(evt);
            }
        });
        jMenu3.add(jSearchVisibleMenuItem);

        jMenuBar1.add(jMenu3);

        jMenu2.setText("Extra");

        jMenuItem3.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.ALT_MASK));
        jMenuItem3.setText("Log snapshot");
        jMenuItem3.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                menuSnapshotClicked(evt);
            }
        });
        jMenu2.add(jMenuItem3);

        jMenuItemDetectPlayer.setText("Detect Flash Player");
        jMenuItemDetectPlayer.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemDetectPlayerActionPerformed(evt);
            }
        });
        jMenu2.add(jMenuItemDetectPlayer);
        jMenu2.add(jSeparator1);

        jMenuItem2.setText("Options...");
        jMenuItem2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                menuOptionsClicked(evt);
            }
        });
        jMenu2.add(jMenuItem2);

        jMenuItem4.setText("About");
        jMenuItem4.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                aboutClicked(evt);
            }
        });
        jMenu2.add(jMenuItem4);

        jMenuBar1.add(jMenu2);

        setJMenuBar(jMenuBar1);

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 613, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 333, Short.MAX_VALUE)
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jFilterCheckboxChecked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jFilterCheckboxChecked
        if (!settings.isUIActionsAvailable()) return;
        controller.filterClicked(jFilterCheckbox.isSelected(), (String)jSearchComboBox.getSelectedItem());
}//GEN-LAST:event_jFilterCheckboxChecked

    private void jTraceTextAreaKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTraceTextAreaKeyPressed
        if (!settings.isUIActionsAvailable()) return;
        controller.textAreaKeyPressed(jTraceTextArea.getSelectedText(), evt);
}//GEN-LAST:event_jTraceTextAreaKeyPressed

    private void jAutorefreshCheckBoxjAutorefreshCheckboxChecked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jAutorefreshCheckBoxjAutorefreshCheckboxChecked
        if (!settings.isUIActionsAvailable()) return;
        controller.autoRefreshClicked(jAutorefreshCheckBox.isSelected());
}//GEN-LAST:event_jAutorefreshCheckBoxjAutorefreshCheckboxChecked

    private void jOnTopCheckboxChecked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jOnTopCheckboxChecked
        if (!settings.isUIActionsAvailable()) return;
        controller.alwaysOnTopClicked(jOnTopCheckbox.isSelected());
}//GEN-LAST:event_jOnTopCheckboxChecked

    private void jClearTraceButtondeleteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jClearTraceButtondeleteActionPerformed
        if (!settings.isUIActionsAvailable()) return;
        controller.clearTraceClicked();
}//GEN-LAST:event_jClearTraceButtondeleteActionPerformed

    private void jTraceTextAreaMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTraceTextAreaMousePressed
        if (!settings.isUIActionsAvailable()) return;
        controller.textAreaMousePressed();
    }//GEN-LAST:event_jTraceTextAreaMousePressed

    private void jClearActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jClearActionPerformed
        if (!settings.isUIActionsAvailable()) return;
        controller.clearSearchClicked();
}//GEN-LAST:event_jClearActionPerformed

    private void logTypeComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_logTypeComboActionPerformed
        if (!settings.isUIActionsAvailable()) return;
        controller.setLogTypeClicked(String.valueOf(logTypeCombo.getSelectedIndex()));
    }//GEN-LAST:event_logTypeComboActionPerformed

    private void menuCopyAllClicked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuCopyAllClicked
        if (!settings.isUIActionsAvailable()) return;
        controller.copyAllClicked(jTraceTextArea.getText());
    }//GEN-LAST:event_menuCopyAllClicked

    private void menuOptionsClicked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuOptionsClicked
        if (!settings.isUIActionsAvailable()) return;
        controller.openOptionsClicked();
    }//GEN-LAST:event_menuOptionsClicked

    private void menuSnapshotClicked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuSnapshotClicked
        if (!settings.isUIActionsAvailable()) return;
        controller.snapshotClicked(jTraceTextArea.getText());
    }//GEN-LAST:event_menuSnapshotClicked

    private void aboutClicked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_aboutClicked
        if (!settings.isUIActionsAvailable()) return;
        controller.aboutOpenClicked();
    }//GEN-LAST:event_aboutClicked

    private void jTraceTextAreaMouseMoved(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTraceTextAreaMouseMoved
        if (!settings.isUIActionsAvailable()) return;
        controller.textAreaMouseMoved(evt);
    }//GEN-LAST:event_jTraceTextAreaMouseMoved

    private void jTraceTextAreaMouseExited(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTraceTextAreaMouseExited
        if (!settings.isUIActionsAvailable()) return;
        controller.textAreaMouseExited(evt);
    }//GEN-LAST:event_jTraceTextAreaMouseExited

    private void formWindowDeactivated(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowDeactivated
        if (!settings.isUIActionsAvailable()) return;
        controller.formWindowDeactivated();
    }//GEN-LAST:event_formWindowDeactivated

    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
        if (!settings.isUIActionsAvailable()) return;
        controller.onClose();
    }//GEN-LAST:event_formWindowClosing

    private void jTraceTextAreaMouseWheelMoved(java.awt.event.MouseWheelEvent evt) {//GEN-FIRST:event_jTraceTextAreaMouseWheelMoved
        if (!settings.isUIActionsAvailable()) return;
        traceAreaScrollBar.dispatchEvent(evt);
        checkNeedScrollDown();
        controller.traceAreaMouseWheel(evt);
    }//GEN-LAST:event_jTraceTextAreaMouseWheelMoved

    private void formWindowLostFocus(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowLostFocus
        if (!settings.isUIActionsAvailable()) return;
        controller.formWindowDeactivated();
    }//GEN-LAST:event_formWindowLostFocus

    private void jSearchComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jSearchComboBoxActionPerformed
//        if (!settings.isUIActionsAvailable()) return;
//        if (evt.getActionCommand().equals("comboBoxEdited")) {
//             controller.searchComboboxChanged((String)jSearchComboBox.getSelectedItem());
//        }
    }//GEN-LAST:event_jSearchComboBoxActionPerformed

    private void jRegexpCheckboxChecked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRegexpCheckboxChecked
        if (!settings.isUIActionsAvailable()) return;
        controller.regexpClicked(jRegexpCheckbox.isSelected());
    }//GEN-LAST:event_jRegexpCheckboxChecked

    private void jTraceTextAreaMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTraceTextAreaMouseClicked
        if (!settings.isUIActionsAvailable()) return;
        if (evt.getClickCount() == 2) {
            controller.textAreaDoubleClicked(evt.getPoint());
        } else if (evt.getButton() == MouseEvent.BUTTON3) {
            controller.textAreaRightClicked(evt.getPoint());
        }
    }//GEN-LAST:event_jTraceTextAreaMouseClicked

    private void jTraceTextAreaMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTraceTextAreaMouseReleased
        if (!settings.isUIActionsAvailable()) return;
        controller.textAreaMouseReleased();
    }//GEN-LAST:event_jTraceTextAreaMouseReleased

    private void jMenuItemDetectPlayerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemDetectPlayerActionPerformed
        controller.detectFlashPlayer();
    }//GEN-LAST:event_jMenuItemDetectPlayerActionPerformed

    private void menuSearchVisibleClicked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuSearchVisibleClicked
        controller.searchPanelVisibleClicked();
    }//GEN-LAST:event_menuSearchVisibleClicked

    private void menuLineNumbersVisibleClicked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuLineNumbersVisibleClicked
        controller.lineNumbersVisibleClicked();
    }//GEN-LAST:event_menuLineNumbersVisibleClicked

    private void jWordWrapCheckBoxMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jWordWrapCheckBoxMenuItemActionPerformed
        if (!settings.isUIActionsAvailable()) return;
        controller.wordWrapClicked();
    }//GEN-LAST:event_jWordWrapCheckBoxMenuItemActionPerformed

    private void jSearchComboBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_jSearchComboBoxItemStateChanged
        if (!settings.isUIActionsAvailable()) return;
        controller.searchComboboxChanged((String)jSearchComboBox.getSelectedItem(), false);
    }//GEN-LAST:event_jSearchComboBoxItemStateChanged

    // Variables declaration - do not modify//GEN-BEGIN:variables
    public javax.swing.JCheckBox jAutorefreshCheckBox;
    public javax.swing.JButton jButton1;
    public javax.swing.JButton jClearTraceButton;
    public javax.swing.JCheckBox jFilterCheckbox;
    private javax.swing.JCheckBoxMenuItem jLineNumbersCheckBoxMenuItem;
    private javax.swing.JTextArea jLineNumbersTextArea;
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenu jMenu2;
    private javax.swing.JMenu jMenu3;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JMenuItem jMenuItem1;
    private javax.swing.JMenuItem jMenuItem2;
    private javax.swing.JMenuItem jMenuItem3;
    private javax.swing.JMenuItem jMenuItem4;
    private javax.swing.JMenuItem jMenuItemDetectPlayer;
    public javax.swing.JCheckBox jOnTopCheckbox;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    public javax.swing.JCheckBox jRegexpCheckbox;
    private javax.swing.JPanel jScrollHighlight;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JComboBox jSearchComboBox;
    private javax.swing.JPanel jSearchPanel;
    private javax.swing.JCheckBoxMenuItem jSearchVisibleMenuItem;
    private javax.swing.JSeparator jSeparator1;
    public javax.swing.JTextArea jTraceTextArea;
    private javax.swing.JCheckBoxMenuItem jWordWrapCheckBoxMenuItem;
    public javax.swing.JComboBox logTypeCombo;
    // End of variables declaration//GEN-END:variables

    private boolean needToScrolldown = true;
    private boolean isCapturingScroll = false;

    private JScrollBar traceAreaScrollBar;
    private SettingsModel settings;
    private VizzyController controller;

    public VizzyForm(VizzyController controller, SettingsModel settings) {
        super("Vizzy Flash Tracer");
        this.controller = controller;
        this.settings = settings;
    }
    @Override
    public void onInit() {
        initComponents();
        FilterDocument filterDocument = new FilterDocument();
        jTraceTextArea.setDocument(filterDocument);
        searchComboboxBorder = ((JComponent)jSearchComboBox.getEditor().getEditorComponent()).getBorder();
    }
    @Override
    public void onAfterInit() {
        initVars();
        initListeners();
        setVisible(true);
    }

    private void initListeners() {
        traceAreaScrollBar.addMouseListener(new MouseListener() {
            public void mouseClicked(MouseEvent e) {
            }
            public void mousePressed(MouseEvent e) {
                isCapturingScroll = true;
            }
            public void mouseReleased(MouseEvent e) {
                isCapturingScroll = false;
            }
            public void mouseEntered(MouseEvent e) {
            }
            public void mouseExited(MouseEvent e) {
            }
        });

        traceAreaScrollBar.addAdjustmentListener(new AdjustmentListener() {
            public void adjustmentValueChanged(AdjustmentEvent e) {
                if (isCapturingScroll) {
                    checkNeedScrollDown();
                }
            }
        });

        jSearchComboBox.getEditor().getEditorComponent().addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {
            }
            @Override
            public void keyPressed(KeyEvent e) {
            }
            @Override
            public void keyReleased(KeyEvent e) {
                if (!settings.isUIActionsAvailable()) return;
                controller.searchComboboxChanged((String)jSearchComboBox.getEditor().getItem(), 
                        e.getKeyCode() == KeyEvent.VK_ENTER);
            }
            
            
        });
        
        KeyStroke ctrlH = KeyStroke.getKeyStroke(KeyEvent.VK_E,
                InputEvent.CTRL_DOWN_MASK, true);
        InputMap inputMap = jPanel1.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        inputMap.put(ctrlH, "my_action");
        ActionMap actionMap = jPanel1.getActionMap();
        actionMap.put("my_action", new Action() {
            public Object getValue(String key) {
                return "";
            }
            public void putValue(String key, Object value) {
            }
            public void setEnabled(boolean b) {
            }
            public boolean isEnabled() {
                return true;
            }
            public void addPropertyChangeListener(PropertyChangeListener listener) {
            }
            public void removePropertyChangeListener(PropertyChangeListener listener) {
            }
            public void actionPerformed(ActionEvent e) {
                controller.clearTraceClicked();
            }
        });

//        jTraceTextArea.getDocument().addDocumentListener(new DocumentListener(){
//            @Override
//            public void changedUpdate(DocumentEvent de) {
//                populateLineNumbers();
//            }
//
//            @Override
//            public void insertUpdate(DocumentEvent de) {
//                populateLineNumbers();
//            }
//
//            @Override
//            public void removeUpdate(DocumentEvent de) {
//                populateLineNumbers();
//            }
//
//        });

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                populateLineNumbersDelayed();
            }
        });
    }

    private void populateLineNumbers() {
        try {
            if (!settings.isLineNumbersVisible()) {
                return;
            }

            int traceLinesCount = jTraceTextArea.getLineCount();

            Dimension tracePrefSize = jTraceTextArea.getPreferredSize();
            Dimension lineNumbersPrefSize = jLineNumbersTextArea.getPreferredSize();

            jLineNumbersTextArea.setPreferredSize(new Dimension(lineNumbersPrefSize.width, tracePrefSize.height));

            int linesCount = tracePrefSize.height / ((LineHeightTextArea) jLineNumbersTextArea).getRowHeightPubl();
            if (linesCount < traceLinesCount) {
                return;
            }

            int existingLinesCount = jLineNumbersTextArea.getLineCount();
            if (existingLinesCount == linesCount) {
                return;
            }

            int startValue = 1;
            StringBuilder sb = new StringBuilder();
            if (existingLinesCount < linesCount) {
                startValue = existingLinesCount;
                for (int i = startValue; i <= linesCount; i++) {
                    sb.append(i).append(Conf.newLine);
                }
                jLineNumbersTextArea.append(sb.toString());
            }
        } catch (Exception e) {
        }
    }

    private void populateLineNumbersDelayed(){
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                populateLineNumbers();
            }
        });
    }

    private void initVars() {
        traceAreaScrollBar = jScrollPane1.getVerticalScrollBar();
        getHighLightScroll().setTa(jTraceTextArea);
    }

    private void checkNeedScrollDown() {
        int sum = traceAreaScrollBar.getValue() + traceAreaScrollBar.getVisibleAmount();
        int am = traceAreaScrollBar.getMaximum();
        if (sum >= am) {
            needToScrolldown = true;
        } else {
            needToScrolldown = false;
        }
    }









    
    @Override
    public void onCustomASEditorChanged(String customASEditor) {
        
    }
    @Override
    public void onRefreshFreqChanged(long refreshFreq) {
        
    }
    @Override
    public void onLogTypeChanged(int logType) {
        logTypeCombo.setSelectedIndex(settings.getLogType());
    }
    @Override
    public void onHightlightAllChanged(boolean hightlightAll) {
//        jHighlightAllCheckbox.setSelected(settings.isHightlightAll());
    }
    @Override
    public void onDefaultASEditorChanged(boolean defaultASEditor) {
        
    }
    @Override
    public void onUTFChanged(boolean uTF) {

    }
    @Override
    public void onPolicyLogFileNameChanged(String policyLogFileName) {

    }
    @Override
    public void onFlashLogFileNameChanged(String flashLogFileName) {

    }
    @Override
    public void onFontsChanged(Font[] fonts) {
    }
    @Override
    public void onMainWindowLocationChanged(Rectangle window) {
        setBounds(settings.getMainWindowLocation());
    }
    @Override
    public void onCurrentLogFileChanged(String currentLogFile) {

    }
    @Override
    public void onTraceFontChanged(Font traceFont) {
        jTraceTextArea.setFont(settings.getTraceFont());
        jLineNumbersTextArea.setFont(settings.getTraceFont());
    }
    @Override
    public void onSearchKeywordsChanged(String[] searchKeywords, DefaultComboBoxModel searchKeywordsModel) {
        jSearchComboBox.setModel(settings.getSearchKeywordsModel());
    }
    @Override
    public void onFilterChanged(boolean filter) {
        if (!filter) {
            jTraceTextArea.setText(settings.getTraceContent());
            populateLineNumbersDelayed();
        }
        jFilterCheckbox.setSelected(settings.isFilter());
        updateCommaTooltipCheckBox();
//        jHighlightAllCheckbox.setEnabled(!settings.isFilter());
        jRegexpCheckbox.setEnabled(!settings.isFilter());
        ((JScrollHighlightPanel) jScrollHighlight).setAllowHighlighting(!settings.isFilter());
        ((JScrollHighlightPanel) jScrollHighlight).setIndexes(null);
    }
    @Override
    public void onAutoRefreshChanged(boolean autoRefresh) {
        jAutorefreshCheckBox.setSelected(settings.isAutoRefresh());
    }
    @Override
    public void onWordWrapChanged(boolean wordWrap) {
        jWordWrapCheckBoxMenuItem.setSelected(settings.isWordWrap());
        jTraceTextArea.setLineWrap(settings.isWordWrap());
    }
    @Override
    public void onCheckUpdatesChanged(boolean checkUpdates) {

    }
    @Override
    public void onMaxNumLinesEnabledChanged(boolean maxNumLinesEnabled) {

    }
    @Override
    public void onMaxNumLinesChanged(long maxNumLines) {

    }
    @Override
    public void onRestoreOnUpdateChanged(boolean restoreOnUpdate) {

    }
    @Override
    public void onAlwaysOnTopChanged(boolean alwaysONTop) {
        jOnTopCheckbox.setSelected(settings.isAlwaysOnTop());
        setAlwaysOnTop(settings.isAlwaysOnTop());
    }
    @Override
    public void onLastUpdateDateChanged(Date lastUpdateDate) {

    }
    @Override
    public void onDefaultFontChanged(String defaultFont) {

    }
    @Override
    public void onSetFontNamesChanged(String[] fontNames) {

    }
    @Override
    public void onRecentHashChanged(String recentHash) {

    }
    @Override
    public void onTraceContentChanged(String traceContent) {
        if ("".equals(traceContent) || traceContent == null) {
            jTraceTextArea.setText(settings.getTraceContent());
            populateLineNumbersDelayed();
            needToScrolldown = true;
            ((JScrollHighlightPanel) jScrollHighlight).setIndexes(null);
        } else {
            int selStart = jTraceTextArea.getSelectionStart();
            int selEnd = jTraceTextArea.getSelectionEnd();
            boolean filteringOff = !(settings.getSearcher().isWasSearching() && settings.isFilter());
            if (filteringOff) {
                jTraceTextArea.setText(traceContent);
                populateLineNumbersDelayed();
            }
            if (needToScrolldown) {
                jTraceTextArea.setCaretPosition(jTraceTextArea.getDocument().getLength());
            } else {
                if (jTraceTextArea.getDocument().getLength() > selEnd
                        && selEnd != -1
                        && selStart != -1
                        && selEnd > selStart) {
                    jTraceTextArea.setSelectionStart(selStart);
                    jTraceTextArea.setSelectionEnd(selEnd);
                }
            }
            if (settings.isRestoreOnUpdate()) {
                setExtendedState(JFrame.NORMAL);
                repaint();
            }
        }
    }
    @Override
    public JTextArea getTextArea() {
        return jTraceTextArea;
    }

    @Override
    public void onSearch(String word, SearchResult searchResult, boolean scrollToSearchResult) {
        if (searchResult != null) {
            highlightSearchComboBox(true, true);
            if (scrollToSearchResult) {
                needToScrolldown = false;
                try {
                    jTraceTextArea.scrollRectToVisible(jTraceTextArea.modelToView(searchResult.offset));
                } catch (BadLocationException e) {
                }
            }
        } else {
            highlightSearchComboBox(true, false);
        }
    }

    @Override
    public void afterFilter(String content) {
        try {
            jTraceTextArea.setText(content);
            FilterDocument document = (FilterDocument) jTraceTextArea.getDocument();
            document.writeUnlock2();
            if (needToScrolldown) {
                jTraceTextArea.setCaretPosition(jTraceTextArea.getDocument().getLength());
            }
            populateLineNumbersDelayed();
        } catch (Exception ex) {
            log.warn("onSearch()", ex);
        }
        highlightSearchComboBox(false, false);
    }
    @Override
    public void beforeFilter() {
        try {
            FilterDocument document = (FilterDocument) jTraceTextArea.getDocument();
            document.writeLock2();
            jTraceTextArea.setText(settings.getTraceContent());
        } catch (Exception ex) {
            log.warn("onSearch()", ex);
        }
    }
    @Override
    public void onOptionsClosed() {
//        jTraceTextArea.setText("");
    }
    @Override
    public void onHighlightTraceKeyword(String text) {
        jSearchComboBox.setSelectedItem(text);
    }

    @Override
    public void onSearchCleared() {
        jTraceTextArea.setText(settings.getTraceContent());
        if (!jSearchComboBox.getSelectedItem().equals("")) {
            jSearchComboBox.setSelectedItem("");
        }
        highlightSearchComboBox(false, false);
        ((JScrollHighlightPanel)jScrollHighlight).setIndexes(null);
        populateLineNumbersDelayed();
        jSearchComboBox.requestFocus();
    }

    @Override
    public void onAlwaysOnTopUIChanged(boolean alwaysOnTop) {
        setAlwaysOnTop(alwaysOnTop);
    }

    @Override
    public JScrollHighlightPanel getHighLightScroll() {
        return (JScrollHighlightPanel)jScrollHighlight;
    }
    @Override
    public void onEnableTraceClickChanged(boolean enableStackTraceClick) {
    }
    @Override
    public void onEnableCodePopupChanged(boolean enableCodePopup) {
    }
    @Override
    public void onShowNewFeaturesPanel() {
        if (newFeaturesPanel == null) {
            newFeaturesPanel = new NewFeaturesPanel("<html>Did you know that it's possible to highlight"
                    + " lines based on custom keywords? Read more...</html>",
                    new INewFeaturesListener() {
                public void click() {
                    removeNewFeaturesPanel();
                    if (Desktop.isDesktopSupported()) {
                        try {
                              Desktop.getDesktop().browse(new URI(Conf.URL_PROJECT_HOME + "wiki/Features#Custom_highlights"));
                        } catch (Exception ex) {
                        }
                    }
                }
                public void close() {
                    removeNewFeaturesPanel();
                }
            });
            
            jPanel1.add(newFeaturesPanel, jPanel1.getComponentCount() - 2);
            jPanel1.validate();
            jPanel1.repaint();
        }
    }
    @Override
    public void onNewFeaturesPanelShownChanged(boolean wasNewFeaturesPanelShown) {
    }


    private void removeNewFeaturesPanel() {
        controller.newFeaturesPanelClosed();
        newFeaturesPanel.dispose();
        jPanel1.remove(newFeaturesPanel);
        newFeaturesPanel = null;
        jPanel1.validate();
        jPanel1.repaint();
    }

    private void updateCommaTooltipCheckBox() {
        if (settings.isFilter()) {
            jSearchComboBox.setToolTipText("Use comma to separate multiple keywords");
        } else {
            jSearchComboBox.setToolTipText(null);
        }
    }

    private void highlightSearchComboBox(boolean show, boolean found) {
        JComponent editor = (JComponent)jSearchComboBox.getEditor().getEditorComponent();
        if (!show) {
            editor.setBorder(searchComboboxBorder);
        } else {
            if (found) {
                editor.setBorder(BorderFactory.createLineBorder(Conf.FOUND_SEARCH_COMBO_COLOR, 2));
            } else {
                editor.setBorder(BorderFactory.createLineBorder(Conf.NOTFOUND_SEARCH_COMBO_COLOR, 2));
            }
        }
    }

    public void onRegexpChanged(boolean regexp) {
        jRegexpCheckbox.setSelected(regexp);
    }

    public void onFontColorChanged(Color fontColor) {
        jTraceTextArea.setForeground(fontColor);
    }

    public void onBgColorChanged(Color bgColor) {
        jTraceTextArea.setBackground(bgColor);
    }

    public void onEnableParsingSourceLines(boolean enableParsingSourceLines) {
    }

    public void closeApp() {
        dispose();
    }

    public void onSearchVisible(boolean searchVisible) {
        if (searchVisible && !jPanel1.isAncestorOf(jSearchPanel)) {
            jPanel1.add(jSearchPanel, 0);
            jPanel1.validate();
            jPanel1.repaint();
            jSearchComboBox.requestFocus();
        } else if (!searchVisible && jPanel1.isAncestorOf(jSearchPanel)) {
            jPanel1.remove(jSearchPanel);
            jPanel1.validate();
            jPanel1.repaint();
            if (needToScrolldown) {
                jTraceTextArea.setCaretPosition(jTraceTextArea.getDocument().getLength());
            }
        }
        jSearchVisibleMenuItem.setSelected(searchVisible);
    }

    public void onLineNumbersVisible(boolean lineNumbersVisible) {
        if (lineNumbersVisible) {
            jScrollPane1.setRowHeaderView(jLineNumbersTextArea);
        } else {
            jScrollPane1.setRowHeaderView(null);
        }
        jPanel1.validate();
        jPanel1.repaint();
        jLineNumbersCheckBoxMenuItem.setSelected(lineNumbersVisible);

        if (lineNumbersVisible) {
            populateLineNumbersDelayed();
        }
    }

    public JScrollPane getScrollPane() {
        return jScrollPane1;
    }

    public void onHighlightColorData(List<HighlightsColorData> highlightColorData) {
        
    }

}
